import { Service } from "@/middleware/response";
import { CodeGenerateModel } from "@/models/admin/CodeGenerate";
import { CodeGenerateFieldModel } from "@/models/admin/CodeGenerateField";
import { CodeGenerate } from "@/types/admin/codeGenerate";
import { PageReq } from "@/types/common/common";
import { catchError, createRecord, deleteRecord, getPageList, GetPageListOptions, getRecord, updateRecord } from "@/utils/db";
import path from "path";
import { deleteFolder, writeFile } from "@/utils/file";
import { getControllerCode, getModelCode, getServiceCode, getTypeCode } from "@/templates/service/codeGenerate";
import lodash from "lodash";
import { getAdminApiCode, getAdminListPageCode, getAdminTypeCode } from "@/templates/admin/codeGenerate";
import archiver from "archiver";
import fs from "fs";
import { Types } from "mongoose";
import { PermissionModel } from "@/models/admin/Permission";

export const getCodeGenerateListService: Service = async (req, res) => {
    const { page, pageSize, ...match } = req.query;
    const { modelName, collectionName } = match;
    const options: GetPageListOptions<CodeGenerate> = {
        model: CodeGenerateModel,
        params: req.query as PageReq,
        $project: { fields: 0 },
    };
    if (modelName || collectionName) options.$match = {};
    if (typeof modelName === "string") options.$match!.modelName = { $regex: RegExp(modelName), $options: "i" };
    if (typeof collectionName === "string")
        options.$match!.collectionName = {
            $regex: RegExp(collectionName),
            $options: "i",
        };
    catchError({
        async operation() {
            const { total, list } = await getPageList(options);
            res.sendResponse!(200, { total, list });
        },
        res,
        type: "查询",
    });
};

export const getCodeGenerateService: Service = async (req, res) => {
    const { _id } = req.params;
    catchError({
        async operation() {
            return await getRecord({
                model: CodeGenerateModel,
                _id,
                childFields: [{ localField: "fields", from: "codegeneratefields" }],
            });
        },
        res,
        type: "查询",
    });
};

export const createCodeGenerateService: Service = async (req, res) => {
    const { fields, ...data } = req.body;
    catchError({
        async operation() {
            const childFields = [{ key: "fields", value: fields, model: CodeGenerateFieldModel }];
            await createRecord({ model: CodeGenerateModel, childFields, data });
        },
        res,
        type: "创建",
    });
};

export const updateCodeGenerateService: Service = async (req, res) => {
    const { _id, fields, ...data } = req.body;
    catchError({
        async operation() {
            const childFields = [{ key: "fields", value: fields, model: CodeGenerateFieldModel }];
            await updateRecord({ model: CodeGenerateModel, _id, childFields, data });
        },
        res,
        type: "更新",
    });
};

export const deleteCodeGenerateService: Service = async (req, res) => {
    const { _id } = req.body;
    catchError({
        async operation() {
            await deleteRecord({
                model: CodeGenerateModel,
                _id,
                childFields: [{ key: "fields", model: CodeGenerateFieldModel }],
            });
        },
        res,
        type: "删除",
    });
};

const generateCode = async (_id: string) => {
    const data = await getRecord({
        model: CodeGenerateModel,
        _id,
        childFields: [{ localField: "fields", from: "codegeneratefields" }],
    });
    const { modelName, resultTypes } = data as CodeGenerate;

    // 用于存储所有的 writeFile Promise
    const writePromises: Promise<unknown>[] = [];

    const codeObj: Record<string, any> = {
        service: {
            src: {
                types: {},
                models: {},
                services: {},
                controllers: {},
            },
        },
    };
    // 服务端代码，分管理端、客户端
    resultTypes.forEach(resultType => {
        const typeCode = getTypeCode(data);
        const smallHump = lodash.lowerFirst(modelName);
        const typeFolderPath = path.resolve(__dirname, `../../../static/${_id}/service/src/types/${resultType}/${smallHump}.ts`);
        writePromises.push(writeFile(typeFolderPath, typeCode));

        const modelCode = getModelCode(data, resultType);
        const modelFolderPath = path.resolve(__dirname, `../../../static/${_id}/service/src/models/${resultType}/${modelName}.ts`);
        writePromises.push(writeFile(modelFolderPath, modelCode));

        const serviceCode = getServiceCode(data, resultType);
        const serviceFolderPath = path.resolve(__dirname, `../../../static/${_id}/service/src/services/${resultType}/${smallHump}.ts`);
        writePromises.push(writeFile(serviceFolderPath, serviceCode));

        const controllerCode = getControllerCode(data, resultType);
        const controllerFolderPath = path.resolve(__dirname, `../../../static/${_id}/service/src/controllers/${resultType}/${smallHump}.ts`);
        writePromises.push(writeFile(controllerFolderPath, controllerCode));


        codeObj.service.src.types[resultType] = { [`${smallHump}.ts`]: typeCode };
        codeObj.service.src.models[resultType] = { [`${modelName}.ts`]: modelCode };
        codeObj.service.src.services[resultType] = { [`${smallHump}.ts`]: serviceCode };
        codeObj.service.src.controllers[resultType] = { [`${smallHump}.ts`]: controllerCode };

        // 前端管理端代码
        if (resultType === "admin") {
            const typeCode = getAdminTypeCode(data);
            const typeFolderPath = path.resolve(__dirname, `../../../static/${_id}/admin/src/typings/api/${smallHump}.ts`);
            writePromises.push(writeFile(typeFolderPath, typeCode));

            const apiCode = getAdminApiCode(data);
            const apiFolderPath = path.resolve(__dirname, `../../../static/${_id}/admin/src/api/${smallHump}.ts`);
            writePromises.push(writeFile(apiFolderPath, apiCode));

            const listCode = getAdminListPageCode(data);
            const listFolderPath = path.resolve(__dirname, `../../../static/${_id}/admin/src/views/${modelName}/${modelName}.tsx`);
            writePromises.push(writeFile(listFolderPath, listCode));

            codeObj.admin = {
                src: {
                    typings: { api: { [`${smallHump}.ts`]: typeCode } },
                    api: { [`${smallHump}.ts`]: apiCode },
                    views: { [modelName]: { [`${modelName}.tsx`]: listCode } },
                },
            };
        }
    });

    await Promise.all(writePromises);
    return codeObj;
};

export const downloadCodeService: Service = async (req, res) => {
    const { _id } = req.query;
    if (!_id || !Types.ObjectId.isValid(_id as string)) throw Error("_id格式错误");
    await generateCode(_id as string);
    const folderPath = path.resolve(__dirname, `../../../static/${_id}`);
    // 检查目录是否存在
    if (!fs.existsSync(folderPath)) return res.sendResponse!(500, null, "代码生成失败");
    // 设置响应头，告诉浏览器返回的是一个下载文件
    res.setHeader("Content-Type", "application/zip");
    res.setHeader("Content-Disposition", `attachment; filename=${_id}.zip`);
    const archive = archiver("zip", {
        zlib: { level: 9 }, // 设置压缩级别
    });
    // 管道将归档内容传递到响应
    archive.pipe(res);
    // 将整个文件夹添加到归档中
    archive.directory(folderPath, false);
    // 完成归档
    try {
        await archive.finalize();
    } catch (err) {
        console.error("归档错误:", err);
        res.sendResponse!(500, null, "归档过程出错");
    }
    deleteFolder(path.resolve(folderPath));
};

export const viewCodeService: Service = async (req, res) => {
    const { _id } = req.query;
    if (!_id || !Types.ObjectId.isValid(_id as string)) throw Error("_id格式错误");
    const codeObj = await generateCode(_id as string);
    res.sendResponse!(200, codeObj);
    const folderPath = path.resolve(__dirname, `../../../static/${_id}`);
    deleteFolder(path.resolve(folderPath));
};

export const generagePermissions: Service = async (req, res) => {
    const { _id } = req.body;
    if (!_id) return res.sendResponse!(400, null, "缺少_id参数");
    catchError({
        async operation() {
            const record = await CodeGenerateModel.findOne({ _id });
            if (!record) return res.sendResponse!(400, null, "未找到该记录");
            const { permissionKey, pageName, modelName } = record;
            if (!permissionKey) return res.sendResponse!(400, null, "该记录未设置权限标识");
            const parentPermission = await PermissionModel.findOne({ key: permissionKey, type: 'menu' });
            if (!parentPermission) return res.sendResponse!(400, null, "未找到父级权限");
            const permissionNamePrefix = pageName ? (pageName.includes('管理') ? pageName.replace('管理', '') : pageName) : modelName;
            const path = `/${permissionKey.split("/").slice(2)}`;
            const permissionList = [
                { name: `创建${permissionNamePrefix}`, key: `${permissionKey}/create`, type: 'pageElement', method: "POST", path },
                { name: `更新${permissionNamePrefix}`, key: `${permissionKey}/update`, type: 'pageElement', method: "PUT", path },
                { name: `删除${permissionNamePrefix}`, key: `${permissionKey}/delete`, type: 'pageElement', method: "DELETE", path },
                { name: `${permissionNamePrefix}列表`, key: `${permissionKey}/list`, type: 'pageElement', method: "GET", path },
                { name: `${permissionNamePrefix}详情`, key: `${permissionKey}/detail`, type: 'pageElement', method: "GET", path },
            ];
            const insertedPermissons = await PermissionModel.insertMany(permissionList);
            const ids = insertedPermissons.map(item => item._id);
            await PermissionModel.updateOne({ _id: parentPermission._id }, { $push: { children: ids } });
            res.sendResponse!(200, insertedPermissons, "权限生成成功");
        },
        res,
        type: "权限生成"
    })
};
